<!-- 图片列表上传器--预览使用的是element-plus的image组件，hover底部展示预览和删除按钮，已做好obs上传和预览，父组件只需传递path列表即可 -->
<script setup lang="ts">
import { ref, watch, onMounted, computed } from 'vue'
import { ElUpload, ElImage, ElMessage } from 'element-plus'
import { Eye, Trash2, ImageUp } from '@vben/icons'
import type { UploadRequestHandler } from 'element-plus'
import { $t } from '@vben/locales';
import { obsUpload } from '#/utils/obs'
import { getStemImgsBlob } from '#/utils/getImgUrl'

defineOptions({ name: 'StemImageUpload' })

interface ImageItem {
  file?: File | Blob
  path?: string
  url?: string
  name?: string
  id?: string
}
const props = withDefaults(defineProps<{
  stemImages: Array<ImageItem>
  limitSizeImg?: number // 可选，限制上传图片的大小，默认5M
  imgNumber?: number // 可选，限制上传图片数量
  showActions?: boolean // 可选，是否展示操作按钮
  actionImgStyle?: string // 可选，图片尺寸样式
  actionBtnStyle?: string // 可选，按钮尺寸样式
}>(), {
  limitSizeImg: 5,
  imgNumber: undefined,
  showActions: true,
  actionImgStyle: '',
  actionBtnStyle: ''
})

const emit = defineEmits(['update:stemImages'])

// 内部图片列表
const internalImageList = ref<Array<ImageItem>>([])
// 已处理过的项目（避免重复创建blob预览）
const processedItems = ref<Set<string>>(new Set())


// 预览对话框
const previewVisible = ref(false)
const previewImageUrl = ref('')
const showPreview = ref(false)

// 从OBS按path加载图片（生成本地blob预览）
const loadItemFromObs = async (item: ImageItem) => {
  if (!item?.path || !item?.id) return

  // 避免重复处理同一项目
  const itemKey = `${item.id}-${item.path}`
  if (processedItems.value.has(itemKey)) return

  // 如果已有有效的预览URL，不重复创建
  if (item.url && (item.url.startsWith('blob:') || item.url.startsWith('data:') || item.url.startsWith('http'))) {
    processedItems.value.add(itemKey)
    return
  }

  try {
    const blob = await getStemImgsBlob(item.path)
    if (blob instanceof Blob) {
      // 填充本地预览URL
      item.url = URL.createObjectURL(blob)
      item.file = blob
      processedItems.value.add(itemKey)
    }
  } catch (e) {
    // 静默失败，保留原数据
    processedItems.value.add(itemKey) // 标记为已处理，避免重试
  }
}

// 初始化数据
onMounted(async () => {
  if (props.stemImages && Array.isArray(props.stemImages)) {
    internalImageList.value = props.stemImages.map((item) => ({
      ...item,
      id: item.id || `img_${Date.now()}_${Math.random()}`,
      url: item.url || (item.file ? URL.createObjectURL(item.file as File) : '')
    }))
    // 对仅有path的图片，从OBS加载展示
    for (const it of internalImageList.value) {
      await loadItemFromObs(it)
    }
  }
})

// 监听外部数据变化，智能合并避免重复处理
watch(() => props.stemImages, async (newVal) => {
  if (newVal?.length) {
    // 智能合并：保留现有项目的预览URL，避免重复创建blob
    const newList = newVal.map((newItem) => {
      // 查找现有项目（通过id或path匹配）
      const existingItem = internalImageList.value.find(existing =>
        (existing.id && newItem.id && existing.id === newItem.id) ||
        (existing.path && newItem.path && existing.path === newItem.path)
      )

      if (existingItem && existingItem.url && (existingItem.url.startsWith('blob:') || existingItem.url.startsWith('data:'))) {
        // 保留现有的预览URL，避免闪烁
        return {
          ...newItem,
          id: existingItem.id || newItem.id || `img_${Date.now()}_${Math.random()}`,
          url: existingItem.url, // 保留现有预览
          file: existingItem.file // 保留现有file
        }
      } else {
        return {
          ...newItem,
          id: newItem.id || `img_${Date.now()}_${Math.random()}`,
          url: newItem.url || (newItem.file ? URL.createObjectURL(newItem.file as File) : '')
        }
      }
    })

    internalImageList.value = newList

    // 只处理新增或需要加载的项目
    for (const it of internalImageList.value) {
      await loadItemFromObs(it)
    }
  } else {
    internalImageList.value = []
    processedItems.value.clear() // 清空处理记录
  }
}, { deep: true })

// 上传前检查
const beforeUpload = (rawFile: File) => {
  const isValidType = ['image/png', 'image/jpeg', 'image/jpg'].includes(rawFile.type)
  const isLt5M = rawFile.size / 1024 / 1024 < props.limitSizeImg

  if (!isValidType) {
    ElMessage.error($t('common.imageFormatTxt2'))
    return false
  }
  if (!isLt5M) {
    ElMessage.error($t('common.imageSizeLimitTxt', [props.limitSizeImg.toString()]))
    return false
  }
  return true
}

// 上传到OBS
const uploadToOBS = (Key: string, file: any): Promise<string> => {
  return new Promise((resolve, reject) => {
    obsUpload({
      Key,
      SourceFile: file
    }, (err: any, _result: any, key: string) => {
      if (err) {
        reject(err)
        return
      }
      resolve(key)
    })
  })
}

// 处理上传（本地预览 + OBS上传）
const handleUpload: UploadRequestHandler = async (options) => {
  const { file } = options
  const id = `img_${Date.now()}_${Math.random()}`
  const newImage: ImageItem = {
    file,
    path: file.name,
    url: URL.createObjectURL(file),
    name: file.name,
    id
  }
  // 添加到内部列表并标记上传中
  internalImageList.value.push(newImage)

  try {
    const obsKey = await uploadToOBS(file.name, file)
    // 仅回写path，保持本地blob预览，不自动替换为签名URL
    const target = internalImageList.value.find(i => i.id === id)
    if (target) {
      target.path = obsKey
    }
    emitUpdate()
    // ElMessage.success($t('common.uploadSuccessTxt'))
  } catch (error) {
    // 失败则移除该项
    const idx = internalImageList.value.findIndex(i => i.id === id)
    if (idx > -1) {
      const it = internalImageList.value[idx]
      if (it?.url && it.url.startsWith('blob:')) URL.revokeObjectURL(it.url)
      internalImageList.value.splice(idx, 1)
      emitUpdate()
    }
    ElMessage.error($t('common.uploadFailTxt'))
  } finally {

  }

  return Promise.resolve()
}

// 删除图片
const deleteImage = (id: string) => {
  const index = internalImageList.value.findIndex(item => item.id === id)
  if (index > -1) {
    // 释放URL对象内存
    const item = internalImageList.value[index]
    if (item && item.url && item.url.startsWith('blob:')) {
      URL.revokeObjectURL(item.url)
    }

    // 从内部列表删除
    internalImageList.value.splice(index, 1)

    emitUpdate()
  }
}

const emitUpdate = () => {
  const updatedList = internalImageList.value.map(item => ({
    file: item.file,
    path: item.path,
    url: item.url,
    name: item.name,
    id: item.id
  }))

  emit('update:stemImages', updatedList)
}

const previewImageUrlList = computed(() => {
  return internalImageList.value.map(item => item.url).filter(Boolean) as any
})
// 预览图片
const previewImage = (url: string) => {
  previewImageUrl.value = url
  previewVisible.value = true
  showPreview.value = true
}

// 获取上传数据
const getData = () => {
  return internalImageList.value
}

defineExpose({
  getData
})
</script>

<template>
  <div class="w-full">
    <!-- 上传区域 -->
    <div class="flex items-start flex-wrap gap-3">
      <!-- 已上传的图片列表 -->
      <div v-for="(image, index) in internalImageList" :key="image.id"
        class="relative w-28 h-16 rounded border border-gray-300 overflow-hidden group transition-shadow"
        :style="actionImgStyle">
        <el-image :src="image.url" :alt="image.name" class="w-full h-full cursor-pointer" fit="contain"
          @click="previewImage(image.url!)" />
        <!-- 操作按钮-预览/删除 -->
        <div v-if="showActions"
          class="absolute bottom-0 left-0 right-0 bg-black flex h-[22px] opacity-0 group-hover:opacity-100 transition-opacity duration-300"
          :style="actionBtnStyle">
          <div @click="previewImage(image.url!)"
            class="flex-1 h-full flex items-center justify-center cursor-pointer transition-colors hover:bg-white hover:bg-opacity-40">
            <Eye class="text-white w-[16px]" />
          </div>
          <div class="w-px h-[22px] bg-white" :style="actionBtnStyle"></div>
          <div @click="deleteImage(image.id!)"
            class="flex-1 h-full flex items-center justify-center cursor-pointer transition-colors hover:bg-white hover:bg-opacity-40">
            <Trash2 class="text-white w-[16px]" />
          </div>
        </div>
        <!-- 预览框 -->
        <el-image-viewer v-if="showPreview && image.url === previewImageUrl" :url-list="previewImageUrlList"
          :initial-index="index" @close="showPreview = false" />
      </div>
      <!-- 上传按钮 -->
      <div v-if="!props.imgNumber || internalImageList.length < props.imgNumber">
        <el-upload action="#" :http-request="handleUpload" :before-upload="beforeUpload"
          accept="image/png,image/jpeg,image/jpg" :auto-upload="true" :show-file-list="false">
          <div
            class="w-28 h-16 border-[1px] border-gray-300 rounded flex flex-col items-center justify-center cursor-pointer transition-all duration-300 hover:border-blue-500 hover:text-blue-500"
            :style="actionImgStyle">
            <!-- 可自定义上传提示信息 -->
            <slot name="upload-info">
              <ImageUp class="text-xl mb-1 w-4 h-4 text-[#595959]" />
              <div class="text-xs text-gray-600">{{ $t('questionBank.uploadImageButton') }}</div>
            </slot>
          </div>
        </el-upload>
      </div>
    </div>
  </div>
</template>
